package com.qingsong.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.qingsong.constant.ML;
import com.qingsong.dto.*;
import com.qingsong.entity.Course;
import com.qingsong.entity.Order;
import com.qingsong.entity.OrderDetail;
import com.qingsong.entity.User;
import com.qingsong.exception.ServiceException;
import com.qingsong.feign.CourseFeign;
import com.qingsong.feign.UserFeign;
import com.qingsong.mapper.OrderDetailMapper;
import com.qingsong.mapper.OrderMapper;
import com.qingsong.service.CartService;
import com.qingsong.service.OrderService;
import com.qingsong.util.MyUtil;
import com.qingsong.vo.OrderSimpleListVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.mybatisflex.core.paginate.Page;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.mybatisflex.core.query.QueryMethods.*;
import static com.qingsong.entity.table.OrderDetailTableDef.ORDER_DETAIL;
import static com.qingsong.entity.table.OrderTableDef.ORDER;

/**
 * 订单表 服务层实现。
 *
 * @author qingsong
 * @since 2024-12-22
 */
@Service
@CacheConfig(cacheNames = "order")
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order>  implements OrderService{

    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private UserFeign userFeign;

    @Autowired
    private CourseFeign courseFeign;

    @Autowired
    private CartService cartService;

    @CacheEvict(allEntries = true)
    @Override
    public boolean insert(OrderInsertDTO dto) {
        // 组装 entity 实体类
        Order order = BeanUtil.copyProperties(dto, Order.class);
        order.setSn(RandomUtil.randomNumbers(19));
        order.setPayType(ML.Order.NO_PAY);
        User user = userFeign.select(dto.getFkUserId()).getData();
        if (ObjectUtil.isNull(user)) {
            throw new ServiceException("订单不存在");
        }
        order.setUsername(user.getUsername());
        order.setCreated(LocalDateTime.now());
        order.setUpdated(LocalDateTime.now());
        return mapper.insert(order) > 0;
    }

    @Cacheable(key = "#p0", condition = "#p0 != null", unless = "#result == null")
    @Override
    public Order select(Long id) {
        return mapper.selectOneWithRelationsById(id);
    }

    @Cacheable(key = "#root.methodName", unless = "#result == null")
    public List<OrderSimpleListVO> simpleList() {
        return QueryChain.of(mapper)
                .orderBy(ORDER.UPDATED.desc())
                .withRelations()
                .listAs(OrderSimpleListVO.class);
    }

    @Cacheable(key = "#root.methodName + ':' + #p0.toString()", condition = "#p0 != null", unless = "#result == null")
    @Override
    public Page<Order> page(OrderPageDTO dto) {
        QueryChain<Order> queryChain = QueryChain.of(mapper)
                .orderBy(ORDER.UPDATED.desc());
        // sn 条件
        String sn = dto.getSn();
        if (ObjectUtil.isNotEmpty(sn)) {
            queryChain.where(ORDER.SN.like(sn));
        }
        // status 条件
        Integer status = dto.getStatus();
        if (ObjectUtil.isNotEmpty(status)) {
            queryChain.where(ORDER.STATUS.like(status));
        }
        // fkUserId 条件
        Long fkUserId = dto.getFkUserId();
        if (ObjectUtil.isNotEmpty(fkUserId)) {
            queryChain.where(ORDER.FK_USER_ID.like(fkUserId));
        }
        return queryChain.withRelations()
                .page(new Page<>(dto.getPageNum(), dto.getPageSize()));
    }

    @CacheEvict(allEntries = true)
    @Override
    public boolean update(OrderUpdateDTO dto) {
        // 组装 entity 实体类
        Order order = BeanUtil.copyProperties(dto, Order.class);
        order.setUpdated(LocalDateTime.now());
        return UpdateChain.of(order)
                .where(ORDER.ID.eq(order.getId()))
                .update();
    }

    @Cacheable(value = "statistics", condition = "#someCondition")
    @Override
    public Map<String, Object> statistics() {
        Map<String, Object> result = new HashMap<>();

        // 统计支付方式比例
        // select gender as name, count(*) as value from user group by gender
        result.put("payTypeCount", QueryChain.of(mapper)
                .select(ORDER.PAY_TYPE.as("name"), QueryMethods.count().as("value"))
                .groupBy(ORDER.PAY_TYPE)
                .orderBy(ORDER.PAY_TYPE.asc())
                .listAs(Map.class));

        // 统计今日订单数
        // select count(*) from user where datediff(curdate(), date_format(created, '%Y-%m-%d')) = 0
        double todayCount = QueryChain.of(mapper)
                .where(dateDiff(currentDate(), dateFormat(ORDER.CREATED, "%Y-%m-%d")).eq(0))
                .count();

        // 统计昨日订单数
        // select count(*) from user where datediff(curdate(), date_format(created, '%Y-%m-%d')) = 1
        double yesterdayCount = QueryChain.of(mapper)
                .where(dateDiff(currentDate(), dateFormat(ORDER.CREATED, "%Y-%m-%d")).eq(1))
                .count();

        // 统计今年订单数
        // select count(*) from user where year(created) = year(current_date);
        double thisYearCount = QueryChain.of(mapper)
                .where(year(ORDER.CREATED).eq(year(currentDate())))
                .count();

        // 统计去年订单总数
        // select count(*) from user where year(created) - year(current_date) = -1;
        double lastYearCount = QueryChain.of(mapper)
                .where(year(ORDER.CREATED).subtract(year(currentDate())).eq(-1))
                .count();

        result.put("todayCount", todayCount);
        result.put("yesterdayCount", yesterdayCount);
        result.put("dayIncrease", MyUtil.increase(todayCount, yesterdayCount));
        result.put("thisYearCount", thisYearCount);
        result.put("lastYearCount", lastYearCount);
        result.put("yearIncrease", MyUtil.increase(thisYearCount, lastYearCount));
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(allEntries = true)
    @Override
    public boolean delete(Long id) {
        // 按订单主键删除订单明细记录
        UpdateChain.of(orderDetailMapper)
                .where(ORDER_DETAIL.FK_ORDER_ID.eq(id))
                .remove();
        // 按订单主键删除一条订单记录
        return mapper.deleteById(id) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(allEntries = true)
    @Override
    public boolean deleteBatch(List<Long> ids) {
        // 按订单主键批量删除订单明细记录
        UpdateChain.of(orderDetailMapper)
                .where(ORDER_DETAIL.FK_ORDER_ID.in(ids))
                .remove();
        // 按订单主键批量删除订单记录
        return mapper.deleteBatchByIds(ids) > 0;
    }


    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(allEntries = true)
    public String prePay(PrePayDTO dto) {

        // 取出用户ID
        Long userId = dto.getFkUserId();

        // 获取该用户的全部订单ID集合
        // select id from order where fk_user_id = ?
        List<Long> orderIds = QueryChain.of(mapper)
                .select(ORDER.ID)
                .where(ORDER.FK_USER_ID.eq(userId))
                .listAs(Long.class);

        // 如果该用户存在订单记录，需要判断是否存在重复购买课程现象
        if (CollUtil.isNotEmpty(orderIds)) {
            // 获取该用户的全部已购买的课程ID集合
            // select fk_course_id from order_detail where fk_order_id in ?
            List<Long> courseIds = QueryChain.of(orderDetailMapper)
                    .select(ORDER_DETAIL.FK_COURSE_ID)
                    .where(ORDER_DETAIL.FK_ORDER_ID.in(orderIds))
                    .listAs(Long.class);

            // 判断是否存在重复购买课程现象：将courseIds变更为两个List的交集结果，有交集说明重复购买
            courseIds.retainAll(dto.getCourseIds());
            if (CollUtil.isNotEmpty(courseIds)) {
                throw new ServiceException("至少一门课程已购买");
            }
        }

        // 组装 entity 实体类
        Order order = BeanUtil.copyProperties(dto, Order.class);
        String sn = RandomUtil.randomNumbers(19);
        order.setSn(sn);
        order.setPayType(ML.Order.NO_PAY);
        order.setStatus(ML.Order.UNPAID);
        order.setInfo("暂无描述信息");
        User user = userFeign.select(userId).getData();
        if (ObjectUtil.isNull(user)) {
            throw new ServiceException("用户不存在");
        }
        order.setUsername(user.getUsername());
        order.setCreated(LocalDateTime.now());
        order.setUpdated(LocalDateTime.now());

        // DB添加订单表记录
        if (mapper.insert(order) <= 0) {
            throw new ServiceException("DB订单添加异常");
        }

        // 批量添加订单明细表记录
        Long orderId = order.getId();
        List<OrderDetail> orderDetails = new ArrayList<>();
        for (Long courseId : dto.getCourseIds()) {
            Course course = courseFeign.select(courseId).getData();
            if (ObjectUtil.isNull(course)) {
                throw new ServiceException("课程不存在");
            }
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setFkCourseId(courseId);
            orderDetail.setFkOrderId(orderId);
            orderDetail.setCourseTitle(course.getTitle());
            orderDetail.setCourseCover(course.getCover());
            orderDetail.setCoursePrice(course.getPrice());
            orderDetail.setCreated(LocalDateTime.now());
            orderDetail.setUpdated(LocalDateTime.now());
            orderDetails.add(orderDetail);
        }
        if (orderDetailMapper.insertBatch(orderDetails) <= 0) {
            throw new ServiceException("DB订单明细表添加异常");
        }

        // 删除购物车表记录
        cartService.deleteByUserIdAndCourseIds(userId, dto.getCourseIds());

        // todo 将订单发送到MQ，延迟15分钟后取出，若仍然是未支付状态

        return sn;
    }

    @CacheEvict(allEntries = true)
    @Override
    public boolean updateStatusBySn(String sn, Integer status) {
        // 根据订单编号更新订单状态
        return UpdateChain.of(mapper)
                .set(ORDER.STATUS, status)
                .set(ORDER.UPDATED, LocalDateTime.now())
                .where(ORDER.SN.eq(sn))
                .update();
    }

    @Override
    public boolean checkStatusBySn(String sn) {
        // 根据订单编号查询订单记录（仅查询支付成功的订单）
        Order order = QueryChain.of(mapper)
                .where(ORDER.SN.eq(sn))
                .and(ORDER.STATUS.eq(ML.Order.PAID))
                .one();
        return ObjectUtil.isNotNull(order);
    }
}
